﻿using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace OrBitDataModule
{
    /// <summary>
    /// 任务调度类
    /// </summary>
    public static class SchedulerHelper
    {
        #region 私有成员
        private static IScheduler scheduler;
        private static object _lock = new object();

        private static IScheduler _scheduler
        {
            get
            {
                if (scheduler == null)
                {
                    lock (_lock)
                    {
                        if (scheduler == null)
                        {
                            scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
                            scheduler.Start();
                        }
                    }
                }
                return scheduler;
            }
        }
        static ConcurrentDictionary<string, Action> jobs { get; }
            = new ConcurrentDictionary<string, Action>();
        #endregion

        #region 外部接口

        /// <summary>
        /// 设置一个时间间隔的循环操作
        /// </summary>
        /// <param name="timeSpan">时间间隔</param>
        /// <param name="action">执行的操作</param>
        /// <returns>任务标识Id</returns>
        public static string SetIntervalJob(TimeSpan timeSpan, Action action)
        {
            string key = Guid.NewGuid().ToString();
            jobs[key] = action;
            IJobDetail job = JobBuilder.Create<Job>()
               .WithIdentity(key)
               .Build();
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(key)
                .StartNow()
                .WithSimpleSchedule(x => x.WithInterval(timeSpan).RepeatForever())
                .Build();
            _scheduler.ScheduleJob(job, trigger);

            return key;
        }

        /// <summary>
        /// 设置每天定时任务
        /// </summary>
        /// <param name="h">时</param>
        /// <param name="m">分</param>
        /// <param name="s">秒</param>
        /// <param name="action">执行的任务</param>
        /// <returns>任务标识Id</returns>
        public static string SetDailyJob(int h, int m, int s, Action action)
        {
            string key = Guid.NewGuid().ToString();
            jobs[key] = action;
            IJobDetail job = JobBuilder.Create<Job>()
               .WithIdentity(key)
               .Build();
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(key)
                .StartNow()
                .WithCronSchedule($"{s} {m} {h} * * ?")//每天定时
                .Build();
            _scheduler.ScheduleJob(job, trigger);

            return key;
        }

        /// <summary>
        /// 设置延时任务,仅执行一次
        /// </summary>
        /// <param name="delay">延时时间</param>
        /// <param name="action">执行的操作</param>
        /// <returns>任务标识Id</returns>
        public static string SetDelayJob(TimeSpan delay, Action action)
        {
            string key = Guid.NewGuid().ToString();
            action += () =>
            {
                RemoveJob(key);
            };
            jobs[key] = action;

            IJobDetail job = JobBuilder.Create<Job>()
               .WithIdentity(key)
               .Build();
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(key)
                .StartAt(DateTime.Now + delay)
                .WithSimpleSchedule(x => x.WithRepeatCount(0).WithInterval(TimeSpan.FromSeconds(10)))
                .Build();
            _scheduler.ScheduleJob(job, trigger);

            return key;
        }

        /// <summary>
        /// 表达式创建任务
        /// </summary>
        /// <param name="cron">表达式</param>
        /// <param name="action">执行的操作</param>
        /// <returns></returns>
        public static string SetCronJob(string cron, Action action)
        {
            string key = Guid.NewGuid().ToString();
            jobs[key] = action;
            IJobDetail job = JobBuilder.Create<Job>()
               .WithIdentity(key)
               .Build();
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(key)
                .StartNow()
                .WithCronSchedule(cron)
                .Build();
            _scheduler.ScheduleJob(job, trigger);

            return key;
        }

        /// <summary>
        /// 删除任务
        /// </summary>
        /// <param name="jobId">任务标识Id</param>
        public static void RemoveJob(string jobId)
        {
            _scheduler.DeleteJob(new JobKey(jobId));
            jobs.TryRemove(jobId, out _);
        }


        private class Job : IJob
        {
            public Task Execute(IJobExecutionContext context)
            {
                return Task.Run(() =>
                  {
                      string jobName = context.JobDetail.Key.Name;
                      if (jobs.ContainsKey(jobName))
                      {
                          jobs[jobName]?.Invoke();
                      }
                  });
            }
        }
        #endregion

        /// <summary>
        /// 获取Cron调度表达式后面5次执行时间
        /// </summary>
        /// <param name="cronExpression"></param>
        /// <returns></returns>
        public static List<string> GetNext5RunTimes(string cronExpression)
        {
            List<string> result = new List<string>();

            if (CronExpression.IsValidExpression(cronExpression))
            {
                CronExpression ce = new CronExpression(cronExpression);
                DateTimeOffset now = DateTimeOffset.Now;
                for (int i = 0; i < 5; i++)
                {
                    var next = ce.GetNextValidTimeAfter(now);
                    now = (DateTimeOffset)next;
                    result.Add(next.ToString());
                }
            }
            return result;
        }
    }
}
